/*
 ------------------------------------------------------------------------------
 Copyright (C) 2006-2007 Team Blur.

 This file is part of the Quantum Engine source code.

 The Quantum Engine source code is free software; you can redistribute it and/or
 modify it under the terms of the GNU General Public License as published by
 the Free Software Foundation; either version 2 of the License, or (at your
 option) any later version.

 The Quantum Engine source code is distributed in the hope that it will be useful,
 but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
 more details.

 You should have received a copy of the GNU General Public License along with
 the Quantum Engine source code; if not, write to the Free Software Foundation, Inc.,
 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 ------------------------------------------------------------------------------
*/


#include "sg_local.h"


/*
 ==================
 SG_AllocEntity
 ==================
*/
entity_t *SG_AllocEntity (void){

	entity_t	*entity;
	int			i;

	// Try to find a free slot
	for (i = MAX_CLIENTS; i < MAX_ENTITIES; i++){
		if (!level.entities[i])
			break;
	}

	if (i == MAX_ENTITIES)
		odSystem->Error(false, "SG_AllocEntity: MAX_ENTITIES hit");

	// Allocate the entity
	level.entities[i] = entity = (entity_t *)odMemory->ClearedAlloc(sizeof(entity_t), TAG_SERVER);

	// Set the entity number
	entity->state.number = i;

	return entity;
}

/*
 ==================
 SG_AllocEntitySlot
 ==================
*/
entity_t *SG_AllocEntitySlot (int number){

	entity_t	*entity;

	// Free anything we have in this slot
	if (level.entities[number])
		SG_FreeEntity(level.entities[number]);

	// Allocate the entity
	level.entities[number] = entity = (entity_t *)odMemory->ClearedAlloc(sizeof(entity_t), TAG_SERVER);

	// Set the entity number
	entity->state.number = number;

	return entity;
}

/*
 ==================
 SG_FreeEntity
 ==================
*/
void SG_FreeEntity (entity_t *entity){

	int		number = entity->state.number;

	// Unlink from world
	SG_UnlinkEntity(entity);

	// Free the entity
	odMemory->Free(entity);

	level.entities[number] = NULL;
}

/*
 ==================
 SG_WriteBaseline
 ==================
*/
void SG_WriteBaseline (entity_t *entity, ByteBuffer *msg){

	entityState_t	nullState;

	memset(&nullState, 0, sizeof(entityState_t));

	msg->WriteBits(entity->baseline.number, ENTITYNUM_BITS);
	msg->WriteByte(entity->baseline.type);

	if (entity->state.type == ET_LIGHT){
		msg->WriteDeltaFloat(nullState.origin.x, entity->baseline.origin.x);
		msg->WriteDeltaFloat(nullState.origin.y, entity->baseline.origin.y);
		msg->WriteDeltaFloat(nullState.origin.z, entity->baseline.origin.z);
		msg->WriteDeltaFloat(nullState.center.x, entity->baseline.center.x);
		msg->WriteDeltaFloat(nullState.center.y, entity->baseline.center.y);
		msg->WriteDeltaFloat(nullState.center.z, entity->baseline.center.z);
		msg->WriteDeltaAngle16(nullState.angles.pitch, entity->baseline.angles.pitch);
		msg->WriteDeltaAngle16(nullState.angles.yaw, entity->baseline.angles.yaw);
		msg->WriteDeltaAngle16(nullState.angles.roll, entity->baseline.angles.roll);
		msg->WriteDeltaFloat(nullState.radius.x, entity->baseline.radius.x);
		msg->WriteDeltaFloat(nullState.radius.y, entity->baseline.radius.y);
		msg->WriteDeltaFloat(nullState.radius.z, entity->baseline.radius.z);
		msg->WriteDeltaFloat(nullState.fovX, entity->baseline.fovX);
		msg->WriteDeltaFloat(nullState.fovY, entity->baseline.fovY);
		msg->WriteDeltaFloat(nullState.falloffRange, entity->baseline.falloffRange);
		msg->WriteBool(entity->baseline.projected);
		msg->WriteBool(entity->baseline.parallel);
		msg->WriteBool(entity->baseline.noShadows);
		msg->WriteDeltaLong(nullState.detailLevel, entity->baseline.detailLevel);
		msg->WriteDeltaLong(nullState.materialIndex, entity->baseline.materialIndex);
		msg->WriteDeltaFloat(nullState.materialParms[0], entity->baseline.materialParms[0]);
		msg->WriteDeltaFloat(nullState.materialParms[1], entity->baseline.materialParms[1]);
		msg->WriteDeltaFloat(nullState.materialParms[2], entity->baseline.materialParms[2]);
		msg->WriteDeltaFloat(nullState.materialParms[3], entity->baseline.materialParms[3]);
		msg->WriteDeltaFloat(nullState.materialParms[4], entity->baseline.materialParms[4]);
		msg->WriteDeltaFloat(nullState.materialParms[5], entity->baseline.materialParms[5]);
		msg->WriteDeltaFloat(nullState.materialParms[6], entity->baseline.materialParms[6]);
		msg->WriteDeltaFloat(nullState.materialParms[7], entity->baseline.materialParms[7]);
	}
	else {
		msg->WriteDeltaLong(nullState.flags, entity->baseline.flags);
		msg->WriteDeltaFloat(nullState.origin.x, entity->baseline.origin.x);
		msg->WriteDeltaFloat(nullState.origin.y, entity->baseline.origin.y);
		msg->WriteDeltaFloat(nullState.origin.z, entity->baseline.origin.z);
		msg->WriteDeltaAngle16(nullState.angles.pitch, entity->baseline.angles.pitch);
		msg->WriteDeltaAngle16(nullState.angles.yaw, entity->baseline.angles.yaw);
		msg->WriteDeltaAngle16(nullState.angles.roll, entity->baseline.angles.roll);
		msg->WriteDeltaLong(nullState.modelIndex, entity->baseline.modelIndex);
		msg->WriteDeltaLong(nullState.clipModelIndex, entity->baseline.clipModelIndex);
		msg->WriteDeltaLong(nullState.materialIndex, entity->baseline.materialIndex);
		msg->WriteDeltaLong(nullState.soundShaderIndex, entity->baseline.soundShaderIndex);
		msg->WriteDeltaFloat(nullState.materialParms[0], entity->baseline.materialParms[0]);
		msg->WriteDeltaFloat(nullState.materialParms[1], entity->baseline.materialParms[1]);
		msg->WriteDeltaFloat(nullState.materialParms[2], entity->baseline.materialParms[2]);
		msg->WriteDeltaFloat(nullState.materialParms[3], entity->baseline.materialParms[3]);
		msg->WriteDeltaFloat(nullState.materialParms[4], entity->baseline.materialParms[4]);
		msg->WriteDeltaFloat(nullState.materialParms[5], entity->baseline.materialParms[5]);
		msg->WriteDeltaFloat(nullState.materialParms[6], entity->baseline.materialParms[6]);
		msg->WriteDeltaFloat(nullState.materialParms[7], entity->baseline.materialParms[7]);
		msg->WriteDeltaLong(nullState.solidBox, entity->baseline.solidBox);
		msg->WriteDeltaLong(nullState.solidContents, entity->baseline.solidContents);
	}
}
